// @Author miaoqing
// @Date 2024/02/22 11:28:00
// @Desc
package network

import (
	"core/component/logger"
	"core/component/router"
	"fmt"
	"net"
	"runtime/debug"
	"sync/atomic"
	"time"
)

type TcpClient struct {
	*NetConn
	Router          *router.Router
	Address         string
	connBuffSize    int64
	OnCloseCallBack func()
	running         atomic.Value
}

// Connect 建立TCP连接
func (c *TcpClient) Connect(addr string) error {

	c.Address = addr

	conn, err := tcpDial(addr, c.connBuffSize)

	if err != nil {
		c.running.Store(false)
		return fmt.Errorf("TCP连接失败 error:%v", err)
	}

	c.Conn = conn

	// 连接和重连都会走这里,检测一下是否需要重置连接数据(重连需要)
	//c.Reset()

	c.running.Store(true)
	// 连接在单独的goroutine中运行
	go c.Run()

	return nil
}

// NewTcpClient 创建tcp连接客户端
func NewTcpClient(msgBuffSize, connBuffSize int64) *TcpClient {
	client := &TcpClient{
		Router:       router.NewRouter(),
		NetConn:      NewNetConn(nil, msgBuffSize),
		connBuffSize: connBuffSize,
	}
	client.running.Store(false)
	client.Impl = client
	return client
}

func (cli *TcpClient) OnClose() {
	// 外部传入的断开连接回调函数
	if cli.OnCloseCallBack != nil {
		cli.OnCloseCallBack()
	}
	cli.running.Store(false)
	logger.Infof("[连接] 断开连接 local:%s remote:%s", cli.LocalAddr(), cli.RemoteAddr())
}

func (cli *TcpClient) IsRunning() bool {
	return cli.running.Load().(bool)
}

func (cli *TcpClient) OnMessage(data []byte) {
	defer func() {
		if err := recover(); err != nil {
			logger.Error("[tcp_client] panic ", err, "\n", string(debug.Stack()))
		}
	}()

	cmd, err := cli.Router.Route(data)
	if err != nil {
		logger.Errorf(err.Error()+":%v", cmd)
		return
	}
}
func (cli *TcpClient) OnConnect() {
	logger.Debugf("[连接] 建立连接 local:%s remote:%s", cli.LocalAddr(), cli.RemoteAddr())
}
func (cli *TcpClient) Marshal(msgID uint16, msg interface{}) ([]byte, error) {
	return cli.Router.Marshal(msgID, msg)
}

func tcpDial(address string, buffSize int64) (*net.TCPConn, error) {

	tcpAddr, err := net.ResolveTCPAddr("tcp4", address)

	if err != nil {
		logger.Error("[连接] 解析失败", address, err)
		return nil, err
	}

	conn, err := net.DialTCP("tcp", nil, tcpAddr)

	if err != nil {
		return nil, err
	}

	//// Try to open keepalive for tcp.
	conn.SetKeepAlive(true)

	conn.SetKeepAlivePeriod(1 * time.Minute)

	// disable Nagle algorithm.
	conn.SetNoDelay(true)

	conn.SetWriteBuffer(int(buffSize))

	conn.SetReadBuffer(int(buffSize))

	return conn, nil
}
